package pl.koziolekweb.javafx.compiler;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.codehaus.plexus.compiler.AbstractCompiler;
import org.codehaus.plexus.compiler.CompilerConfiguration;
import org.codehaus.plexus.compiler.CompilerException;
import org.codehaus.plexus.compiler.CompilerOutputStyle;
import org.codehaus.plexus.util.StringUtils;

/**
 * @plexus.component role="org.codehaus.plexus.compiler.Compiler"
 *                   role-hint="javafxc"
 * 
 * @author koziolek
 * 
 */
public class JavafxcCompiler extends AbstractCompiler {

	private final class JarFilter implements FilenameFilter {
		@Override
		public boolean accept(File dir, String name) {
			return name.endsWith("jar");
		}
	}

	private enum Platform {
		DESKTOP("desktop"), MOBILE("mobile");

		String platform;

		private Platform(String platform) {
			this.platform = platform;
		}
	}

	public JavafxcCompiler() {
		super(CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE, ".fx",
				".class", null);
	}

	@Override
	public List<?> compile(CompilerConfiguration config)
			throws CompilerException {

		File destinationDir = new File(config.getOutputLocation());

		if (!destinationDir.exists()) {
			destinationDir.mkdirs();
		}

		String[] sourceFiles = getSourceFiles(config);

		if ((sourceFiles == null) || (sourceFiles.length == 0)) {
			return Collections.emptyList();
		}

		if ((getLogger() != null) && getLogger().isInfoEnabled()) {
			getLogger().info("Compiling " + sourceFiles.length + " " +
					"source file" + (sourceFiles.length == 1 ? "" : "s") +
					" to " + destinationDir.getAbsolutePath());
		}
		String[] args = buildCompilerArguments(config, sourceFiles);

		List<?> messages = Collections.emptyList();

		messages = compileOutOfProcess(config, getJavafxcExecutable(), args);
		return messages;
	}

	private String getJavafxcExecutable() {
		String exec = "javafxc";
		return exec;
	}

	public String[] createCommandLine(CompilerConfiguration config)
			throws CompilerException {
		return buildCompilerArguments(config, getSourceFiles(config));
	}

	public String[] buildCompilerArguments(CompilerConfiguration config,
			String[] sourceFiles) {
		List<String> args = new ArrayList<String>();
		File destinationDir = new File(config.getOutputLocation());

		args.add("-d");

		args.add(destinationDir.getAbsolutePath());

		List<?> classpathEntries = config.getClasspathEntries();
		if ((classpathEntries != null) && !classpathEntries.isEmpty()) {
			args.add("-classpath");
			args.add(getPathString(classpathEntries) + getJavafxLibs(config));
		} else {
			args.add("-classpath");
			args.add(getJavafxLibs(config));
		}

		List<?> sourceLocations = config.getSourceLocations();
		if ((sourceLocations != null) && !sourceLocations.isEmpty()) {
			args.add("-sourcepath");
			args.add(getPathString(sourceLocations));
		}

		args.addAll(Arrays.asList(sourceFiles));

		if (config.isDebug()) {
			if (StringUtils.isNotEmpty(config.getDebugLevel())) {
				args.add("-g:" + config.getDebugLevel());
			} else {
				args.add("-g");
			}
		}

		if (config.isVerbose()) {
			args.add("-verbose");
		}

		if (config.isShowDeprecation()) {
			args.add("-deprecation");
			config.setShowWarnings(true);
		}

		if (!config.isShowWarnings()) {
			args.add("-nowarn");
		}

		return (String[]) args.toArray(new String[args.size()]);
	}

	private String getJavafxLibs(CompilerConfiguration config) {
		String fxhome = System.getenv("JAVAFX_HOME") + "/lib/shared/";
		String fxlibs = "";
		File fxlib = new File(fxhome);
		for (String name : fxlib.list(new FilenameFilter() {

			@Override
			public boolean accept(File dir, String name) {
				return name.endsWith("jar");
			}
		})) {
			fxlibs += fxlib + name + File.pathSeparator;
		}

		String platformName = config.getCustomCompilerArguments().get(
				"-platform")
				.toString();

		Platform platform = Platform.valueOf(platformName.toUpperCase());
		fxhome = System.getenv("JAVAFX_HOME") + "/lib/" + platform.platform
				+ "/";
		fxlib = new File(fxhome);
		for (String name : fxlib.list(new JarFilter())) {
			fxlibs += fxlib + name + File.pathSeparator;
		}

		return fxlibs;
	}

	private List<?> compileOutOfProcess(CompilerConfiguration config,
			String executable,
			String[] args)
			throws CompilerException {

		String argsS = "";
		for (String arg : args) {
			argsS += " " + arg;
		}
		Runtime runtime = Runtime.getRuntime();

		try {
			runtime.exec(executable + argsS);
		} catch (IOException e) {
			e.printStackTrace();
		}

		return Collections.EMPTY_LIST;
	}
}
